"""
垂直分表:
    按 字段 将一张表拆分成多张表
    对于字段较多的表, 每条记录占用的空间也会较多, 导致每次从硬盘中读取的记录以及查询缓存可缓存的记录数量较少, 影响查询查询效率
    针对字段多的表就可以采用垂直分表来进行拆分, 这样可以减少表体积, 提高查询效率

拆分规则:
    相关性
        可以将字段根据 业务逻辑 和 使用的相关性 进行分表划分
        如: 用户名和密码经常配合使用, 将其分到用户认证表, 生日和邮箱等个人信息经常一起访问, 将其分到用户信息表
    使用频率
        可以将字段根据 常用 和 不常用 进行划分, 并进行分表处理
        如:原始用户表中包含了多个字段, 其中有常用的昵称、手机号等字段, 也包含不常用的邮箱、生日等字段, 可以根据使用频率将其分为两张表: 用户基础信息表 和 用户其他信息表

垂直分库:
    将一个数据库中的多张表拆分到多个数据库(服务器节点)中
    注意点:
    由于 本地事务不支持跨库操作, 所以应该将 有相关联性的表放在同一个库中
    如: 如果后续头条项目垂直分库, 将用户相关的放在数据库1, 文章相关的放在数据库2


分库访问:
    ①通过配置 SQLALCHEMY_BINDS允许设置多个数据库URI,
    ②每个模型类可以通过 __bind_key__ 属性 设置自己对应访问的数据库

    下面项目进行了分库处理,包含两个库 db1 和 db2,
    用户表t_user存储在db1中,而地址表t_adr存储在db2中
"""
from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
# 1.设置多个数据库的地址
app.config['SQLALCHEMY_BINDS'] = {
    'db1': 'mysql://root:mysql@192.168.19.137/db1',
    'db2': 'mysql://root:mysql@192.168.19.137/db2'
}
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_ECHO'] = True

db = SQLAlchemy(app)


# 用户表  存储在db1中
class User(db.Model):
    __tablename__ = 't_user'
    # 2.指定模型类对应访问的数据库
    __bind_key__ = 'db1'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(20))


# 地址表   存储在db2中
class Address(db.Model):
    __tablename__ = 't_adr'
    __bind_key__ = 'db2'
    id = db.Column(db.Integer, primary_key=True)
    detail = db.Column(db.String(20), unique=True)
    user_id = db.Column(db.Integer)


@app.route('/')
def index():
    """增加数据"""
    user1 = User(name='zs')
    db.session.add(user1)
    db.session.flush()
    # db.session.commit()

    adr1 = Address(detail='陆家嘴1号', user_id=user1.id)
    adr2 = Address(detail='中关村1号', user_id=user1.id)
    db.session.add_all([adr1, adr2])

    db.session.commit()  # 虽然只执行一次commit, 但是会向对应的数据库分别提交事务

    return "index"


@app.route('/demo')
def demo():
    """查询数据"""
    # 需求: 查询"张三"的地址信息
    # 由于用户和地址在不同的数据库中,join不能跨库查询,所以必须分别查询, 反之报错
    # adrs = Address.query.join(User, Address.user_id == User.id).filter(User.name == 'zs').all()

    user1 = User.query.filter(User.name == 'zs').first()

    adrs = Address.query.filter(Address.user_id == user1.id).all()
    for adr in adrs:
        print(adr.detail)

    return 'demo'


if __name__ == '__main__':
    db.drop_all()
    db.create_all()  # 由于模型类都指定了对应访问的数据库, 所以可以不设置DATABASE_URI配置
    app.run(debug=True)
